#!/usr/bin/ruby

require 'RMagick'
require 'mysql'
require '../db_setting.rb'

class Layer
  class DBLayer
    attr_reader :db_layer_number, :scale, :weight_min, :weight_max
    attr_reader :label_color, :graph_color, :alpha

    def initialize(layer_num, scale, min, max, label_color, graph_color, alpha)
      @db_layer_number = layer_num
      @scale = scale
      @weight_min = min
      @weight_max = max
      @label_color = label_color
      @graph_color = graph_color
      @alpha = alpha
    end
  end


  def initialize(db, layer_number, layer_width, layer_height, piece_width, piece_height)
    @db = db
    @layer_number = layer_number
    @layer_width  = layer_width
    @layer_height = layer_height
    @piece_width  = piece_width
    @piece_height = piece_height
    @ncol = @layer_width  / @piece_width
    @nrow = @layer_height / @piece_height
    @db_layers = []
  end

  def add_db_layer(db_layer_number, scale, weight_min, weight_max, label_color, graph_color, alpha)
    @db_layers << DBLayer.new(db_layer_number, scale, weight_min, weight_max, label_color, graph_color, alpha)
  end

  def save_images(file_prefix)
    @nrow.times do |y|
      @ncol.times do |x|
        file_name = file_prefix + "_%02d_%04d%04d.png" % [@layer_number, x, y]
        puts file_name
        image = create_one_piece(x, y)
        image.write(file_name)
      end
    end
  end

  def create_one_piece(x, y)
    image = Magick::Image::new(@piece_width, @piece_height){ self.background_color = "white" }

    @db_layers.reverse.each do |db_layer|
      db_layer_img = create_db_layer_img(x, y, db_layer)
      image = image.blend(db_layer_img, db_layer.alpha, 1 - db_layer.alpha)
    end

    return image
  end

  def create_db_layer_img(x, y, db_layer)
    image = Magick::Image::new(@piece_width, @piece_height){ self.background_color = "none" }

    gc_label = Magick::Draw.new
    gc_label.stroke('transparent')
    gc_label.font = '/usr/share/fonts/sazanami-fonts-gothic/sazanami-gothic.ttf'
    gc_label.text_align(Magick::CenterAlign)

    gc_graph = Magick::Draw.new

    sql = "select * from nodes where "
    where_term = [
      "layer = #{db_layer.db_layer_number}",
      "x >= #{(x - 1.0) / @ncol}",
      "x <= #{(x + 2.0) / @ncol}",
      "y >= #{(y - 1.0) / @nrow}",
      "y <= #{(y + 2.0) / @nrow}",
    ]
    where_term << "weight <= #{db_layer.weight_max}" if db_layer.weight_max != -1
    where_term << "weight >= #{db_layer.weight_min}" if db_layer.weight_min != -1
    sql << where_term.join(" and ")

    res = @db.query(sql)
    res.each_hash do |row|
      node_x = row['x'].to_f
      node_y = row['y'].to_f
      label  = row['label']
      weight = row['weight'].to_i
      draw_x = node_x * @layer_width  - x * @piece_width
      draw_y = node_y * @layer_height - y * @piece_height
      margin = 2
      min_font_size = 10

      # draw label
      if true then
        font_size = min_font_size * weight * db_layer.scale
        font_size = [font_size, min_font_size].max
        gc_label.pointsize(font_size)
        gc_label.fill(db_layer.label_color)
        gc_label.fill_opacity(0.5)
        gc_label.text(draw_x, draw_y + margin, label)
      end

      # draw node
      if true then
        r = 3 # * weight * db_layer.scale
        gc_graph.fill(db_layer.graph_color)
        gc_graph.fill_opacity(0.5)
        gc_graph.circle(draw_x, draw_y + r + margin, draw_x - r, draw_y + r + margin)
      end
    end

    begin
      gc_graph.draw(image)
      gc_label.draw(image)
    rescue
    end

    return image
  end
end


# color
color_back_label = "#C0C0C0"
color_back_graph = "#C0C0C0"
color_fore_label = "#1010FF"
color_fore_graph = "#0060FF"


db = Mysql::new(DB_HOST, DB_USER, DB_PASS, DB_NAME)

weight_th = [0, 200, 200, 200, 200]
scale = [0, 1/500.0, 1/500.0, 1/300.0, 1/10.0]

piece_width = 256
piece_height = 256
(0..7).each do |layer_number|
  layer_width  = piece_width  * (2 ** layer_number)
  layer_height = piece_height * (2 ** layer_number)
  layer = Layer.new(db, layer_number, layer_width, layer_height, piece_width, piece_height)

  db_layer = layer_number / 2 + 1

  if (layer_number % 2) == 0 then
    layer.add_db_layer(db_layer, scale[db_layer]/2, weight_th[db_layer], -1, color_fore_label, color_fore_graph, 0.7)
    layer.add_db_layer(db_layer, scale[db_layer]/2, -1, weight_th[db_layer]-1, color_fore_label, color_fore_graph, 0.3)
    layer.add_db_layer(db_layer+1, scale[db_layer+1]/8, weight_th[db_layer+1], -1, color_back_label, color_back_graph, 0.3)
  else
    layer.add_db_layer(db_layer, scale[db_layer], -1, -1, color_fore_label, color_fore_graph, 0.7)
    layer.add_db_layer(db_layer+1, scale[db_layer+1]/4, weight_th[db_layer+1], -1, color_back_label, color_back_graph, 0.7)
    layer.add_db_layer(db_layer+1, scale[db_layer+1]/4, -1, weight_th[db_layer+1]-1, color_back_label, color_back_graph, 0.3)
  end

  layer.save_images("images/img")
end

